#pragma once
#include <brpc/channel.h>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <mutex>
#include "Logger.hpp"

namespace chatroom{
    //某个服务可能有多个信道 需要将信道管理起来
    class ServiceChannel{
        public:
            using Cptr = std::shared_ptr<ServiceChannel>;
            using ChannelPtr = std::shared_ptr<brpc::Channel>;
            ServiceChannel(const std::string& name):_service_name(name),_index(0){}
            // 在提供该服务的主机上添加一条信道,用于rpc请求调用
            void append(const std::string& host)
            {
                // 1 创建信道
                auto channel = std::make_shared<brpc::Channel>();
                brpc::ChannelOptions options;
                // 请求连接时间
                options.connect_timeout_ms = -1;
                // rpc请求超时时间
                options.timeout_ms = -1;
                // 最大重试次数
                options.max_retry = 3;
                // 序列化协议
                options.protocol = "baidu_std";
                int ret = channel->Init(host.c_str(),&options);
                if(ret== -1)
                {
                    Logger_ERROR("增加{}节点主机失败",host);
                    return;
                }
                //建立互斥锁
                std::unique_lock<std::mutex> lock(_mutex);
                HashMap.insert(std::make_pair(host,channel));
                _V1.push_back(channel); 
            }
            // 删除提供该服务的一条信道
            void remove(const std::string& host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = HashMap.find(host);
                if(it == HashMap.end())
                {
                    Logger_ERROR("没有找到要删除的节点主机");
                    return;
                }
                //找到顺序表中要移除的信道
                for(auto vit = _V1.begin();vit != _V1.end();++vit)
                {
                    if(*vit == it->second)
                    {
                        _V1.erase(vit);
                        break;
                    }
                }
                HashMap.erase(it);
            }
            //采用RR轮转的方式选择其中一条信道进行调用
            ChannelPtr choose()
            {
                std::unique_lock<std::mutex> lock(_mutex);
                if(_V1.size()==0)
                {
                    return ChannelPtr();
                }
                int sz = _index++%_V1.size();
                return _V1[sz];
            }
        private:
            std::mutex _mutex;
            std::string _service_name;
            std::vector<ChannelPtr> _V1;
            int32_t _index;
            std::unordered_map<std::string,ChannelPtr> HashMap; //主机与信道之间的映射
    };


    //管理全部服务
    class ServiceManage{
        public:
            using Sptr = std::shared_ptr<ServiceManage>;
            // 可能需要多个服务
            void declared(const std::string& service_name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _follwed.insert(service_name);
            }

            //服务的上线
            void ServiceOnline(std::string service_name,std::string host)
            {
                service_name = getServiceName(service_name);
                std::unique_lock<std::mutex> lock(_mutex);
                auto vit = _follwed.find(service_name);
                if(vit == _follwed.end())
                {
                    Logger_INFO("{}-{}服务上线了,我们并不关心",service_name,host);
                    return;
                }
                auto it = Hashmap.find(service_name);
                if(it == Hashmap.end())
                {
                    auto channel = std::make_shared<ServiceChannel>(service_name);
                    Hashmap.insert(std::make_pair(service_name,channel));
                    channel->append(host);
                    return;
                }else{
                    it->second->append(host);
                }
                Logger_INFO("{}服务上线成功",service_name);
            }
            //服务的下线
            void ServiceOffline(std::string service_name,std::string host)
            {
                service_name = getServiceName(service_name);
                std::unique_lock<std::mutex> lock(_mutex);
                auto vit = _follwed.find(service_name);
                if(vit == _follwed.end())
                {
                    Logger_INFO("{}-{}服务下线了,我们并不关心",service_name,host);
                    return;
                }
                auto it = Hashmap.find(service_name);
                if(it==Hashmap.end())
                {
                    Logger_ERROR("{}-{}:缺少该服务的管理对象",service_name,host);
                    return;
                }
                it->second->remove(host);
                Logger_INFO("{}-{}服务下线成功",service_name,host);
            }
            ServiceChannel::ChannelPtr choose(const std::string& service_name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = Hashmap.find(service_name);
                if(it==Hashmap.end())
                {
                    return ServiceChannel::ChannelPtr();
                }
                return it->second->choose();
            }
        private:
            std::string getServiceName(const std::string &service_instance) {
            auto pos = service_instance.find_last_of('/');
            if (pos == std::string::npos) return service_instance;
            return service_instance.substr(0, pos);
        }
        private:
            std::mutex _mutex;
            std::unordered_set<std::string> _follwed; //关注的有那些服务
            std::unordered_map<std::string,ServiceChannel::Cptr> Hashmap;
    };
}